<?php
/*
    Id:     $Id: $
    File:   REST.php
    Author: John Griffin
    Date:   May 6, 2009

    Description:
*/
require_once 'lib/Error.php';
require_once 'lib/Validator.php';
require_once 'lib/RESTView.php';

class REST {
    private $request_method = null;         // the HTTP reqest method that was used (DELETE, GET, POST, PUT)
    private $resource_file = null;          // the resource that was requested
    private $resource_object = null;        // contents of the resource file as a simple xml object
    private $controller = null;		        // controller defined in the resource file
    private $validator = null;              // used to validate fields before they are handed off to the controller
    private $error = null;                  // used to collect errors
    
    public function __construct ($resource_file) {
        $this->resource_file = $resource_file;
        $method = (isset ($_SERVER['REQUEST_METHOD']) == true) ? $_SERVER['REQUEST_METHOD'] : '';
        $this->requst_method = '';
        switch ($method) {
            case 'GET':
            case 'PUT':
            case 'DELETE':
                $this->request_method = $method;
                break;
            case 'POST':
                // Check to see if this request was sent via an HTML form
                $this->request_method = (isset ($_POST['action']) == true) ? $_POST['action'] : 'POST';
                break;
            default:
                // don't do anything, I'll catch this later on
        }
    }
    
    private function loadResourceFile () {
        // the existence of the file was confirmed prior to the name being passed to us
        $xml = file_get_contents ($this->resource_file, FILE_USE_INCLUDE_PATH);     // using FILE_USE_INCLUDE_PATH may be unsafe
        try {
            $this->resource_object = @new SimpleXMLElement ($xml);
            return true;
        } catch (Exception $e) {
            header('HTTP/1.0 500 Internal Server Error');
            header('Message: Bad XML in resource file');
            return false;
        }
    }
    
    private function newController () {
        $return = false;
        $file = (string) $this->resource_object->resource;
        $controller_name = (string) $this->resource_object->rest->resource['name'];
        
        try {
            @require_once $file;
        } catch (Exception $e) {
            header('HTTP/1.0 500 Internal Server Error');
            header('Not Found: '.$file);
            $return = false;
        }
        
        try {
            $this->controller = new $controller_name ($this->resource_object);
            $return = true;
        } catch (Exception $e) {
            header('HTTP/1.0 500 Internal Server Error');
            header('Not Found: '.$controller_name);
            $return = false;
        }
        return $return;
    }
    
    private function getIds () {
        $unique_key = $this->resource->uniqueKey;
        $return = array ();
        if (isset ($_REQUEST[$unique_key]) == true) {
            if (is_array ($_REQUEST[$unique_key]) == true) {
                $return = $_REQUEST[$unique_key];
            } else {
                $return = array ($_REQUEST[$unique_key]);
            }
        }
        return $return;
    }
    
    private function getArguments () {
        $return = array ();
        if (isset ($this->resource->fields->field) == true) {
            foreach ($this->resource->fields->field as $field) {
                if (isset ($_REQUEST[$field->name]) == true) {
                    $return[$field->name] = $_REQUEST[$field->name];
                }
            }
        }
        return $return;
    }

    private function getModifiers () {
        $return = array ();
        if (isset ($_REQUEST['start']) == true) {
            $return['start'] = $_REQUEST['start'];
        }
        if (isset ($_REQUEST['count']) == true) {
            $return['count'] = $_REQUEST['count'];
        }
        if (isset ($_REQUEST['order']) == true) {
            $return['order'] = $_REQUEST['order'];
        }
        return $return;
    }
    
    public function processErrors () {
        $view = new RESTView ();
        $title = (string) $this->resource_object->title;
        $description = (string) $this->resource_object->description;
        $created = now ();
        $modified = now ();
        $uri = $_SERVER['REQUEST_URI'];
        $view->writeHeading ($title, $description, $created, $modified, $uri);
        $view->processErrors ($this->error);
        $view->writeFooter ();
    }

    private function delete () {
        $ids = $this->getIds ();
        $this->validator->validateIds ($ids);
        if ($this->error->hasErrors () == true) {
            $this->processErrors ();
        } else {
            $this->controller->delete ($ids);
        }
    }
    
    private function get () {
        $arguments = $this->getArguments ();
        $modifiers = $this->getModifiers ();
        $this->validator->validateQueryFilter ($fields, $modifiers);
        if ($this->error->hasErrors () == true) {
            $this->processErrors ();
        } else {
            $this->controller->get ($arguments, $modifiers);
        }
    }
    
    private function post () {
        $arguments = $this->getArguments ();
        $this->validator->validatePostRecord ($arguments);
        if ($this->error->hasErrors () == true) {
            $this->processErrors ();
        } else {
            $result = $this->controller->post ($arguments);
        }
    }
    
    private function put () {
        $arguments = $this->getArguments ();
        $this->validator->validatePutRecord ($arguments);
        if ($this->error->hasErrors () == true) {
            $this->processErrors ();
        } else {
            $result = $this->controller->put ($arguments);
        }
    }
    
    public function exec () {
        $allowed_request_methods = array ('DELETE' => 'delete', 'GET' => 'get', 'POST' => 'post', 'PUT' => 'put');
        
        if (in_array ($this->request_method, array_keys ($allowed_request_methods)) == false) {
                header('HTTP/1.0 405 Method Not Allowed');
                header('Method: '.$this->request_method);
        } else {
            if ($this->loadResourceFile () == true) {
                $this->error = new Error ();
              $this->validator = new Validator ($this->resource_object, $this->error);
              if ($this->newController () == true) {
                    $method = $allowed_request_methods[$this->request_method];
                    $this->$method ();
                }
            }
        }
    }
}
?>
